/** 判断值是否是一个方法或异步方法 */
export function isFunction(value) {
  return value?.constructor == Function || value?.constructor?.name == 'AsyncFunction';
}

/** 判断值是否是异步方法 */
export function isAsyncFunction(value) {
  return value?.constructor?.name == 'AsyncFunction';
}

/** 判断值是否是 Promise */
export function isPromise(value) {
  return value?.constructor == Promise;
}

/** 通过 Promise 来异步处理结果值
 * @template T
 * @param {T | Promise<T>} value - 值或者返回值本来就是 Promise
 * @returns {Promise<T>} - 一定返回 Promise，可以通过 then 来处理返回值
 */
export function asyncResult(value) {
  if (value?.constructor == Promise)
    return value;
  return new Promise(r => r(value));
}

/**
 * 拷贝一个对象的方法，并对执行这个对象的方法增加额外的操作
 * 例如前后端交互的api接口对象，想要发接口后等待接口回调之前显示加载中
 * 则实现如下
 * link(api, i => {
 *  // 立刻弹出组件阻止多次点击，一段时间后正式显示loading
    const loading = popup.show("loading", { delay: 500 });
    // api执行结束后关闭loading
 *  i(arguments).then(i => popup.close(loading));
 * })
 * @param {Object} obj 要拷贝方法的对象
 * @param {Function} link link(func)拷贝的原始方法，link中可以自己在合适的地方调用func(arguments)
 * @param {Object} target 要拷贝到的对象，不传则新建一个对象
 * @param {Function} filter filter(key, value)
 * @returns 拷贝方法之后的新对象
 */
export function link(obj, link, target, filter) {
  const linked = target ?? {};
  for (const key in obj) {
    const value = api[key];
    if (!value || value.constuctor != Function)
      continue;
    if (filter && filter(key, value))
      continue;
    linked[key] = () => link(() => value.apply(linked, arguments));
  }
  return linked;
}